import asyncio
import websockets
import threading
import cv2
import pyvirtualcam
import time
import re
import colorsys
import numpy as np
import random

pattern_RunVideo=r'^run ((?:\S+(?:&\S+)*)+) ((?:random|list|one))$'

HOST = 'localhost'
PORT = 51746
Remark = "循环随机播放多条视频，先播放第一个，后面视频随机播放\r\nrun path1&path2&path3 random\r\n循环顺序播放多条视频run path1&path2&path3 list\r\n仅播放一次\r\nrun path1&path2&path3 one"
 

def GetCommandParam(pattern,command):
    match = re.match(pattern, command)
    if match:
        print("命令格式正确")
        # 提取命令参数
        paths = match.group(1).split('&')
        types = match.group(2)
        # parameters = command.split()[1:]
        print("路径:", paths)
        print("播放类型:", types)
        return paths,types
    else:
        print("命令格式不正确")
        return None
class VideoServer:
    def __init__(self):
        self.is_running = False
        self.ws_server = None
        self.ws = None
        self.video_player = None
        # 创建并启动心跳线程
        self.heartbeat = threading.Thread(target=self.heartbeat)
        self.heartbeat.start()
    def start(self):
        self.ws_server = websockets.serve(self.websocket_handler, HOST, PORT)
        print(HOST, PORT,'服务已启动，等待连接...')
        asyncio.get_event_loop().run_until_complete(self.ws_server)
        asyncio.get_event_loop().run_forever()
         

     
    # WebSocket 服务器处理函数
    async def websocket_handler(self,websocket):
        global global_websocket
        global_websocket = websocket

        print(websocket.remote_address,"连接成功！")
        await websocket.send(Remark)
        self.ws = websocket
        try:
            while True:
                # 接收客户端发送的消息
                message = await websocket.recv()
                # 在这里处理接收到的消息
                print("收到命令:", message)
                try:
                    if(message=="stop"):
                        self.Stop()
                    else:
                        paths,types = GetCommandParam(pattern_RunVideo,message)
                        if paths is None:
                            await websocket.send("命令错误！") 
                            continue
                        else:
                            await self.Play(paths,types,websocket)
                except Exception as e:
                    await websocket.send("执行失败"+e.args[0]) 
                 
                
        except websockets.exceptions.ConnectionClosed:
            print(websocket.remote_address,"连接已断开！")
            await self.Stop()
      

    async def Play(self,_playlist,_playtype,_ws):
        """播放视频"""
        if self.video_player is not None:
            if self.video_player.IsPlaying:
                await self.Stop()
        self.video_player = VideoPlay(_playlist,_playtype,_ws)
        self.video_player.Play()
        # self.thread = threading.Thread(target=self.camera_loop)
        # self.thread.start()
        # print("camera_loop已启动！")

    async def Stop(self):
        if self.video_player is None:
            print("未启用视频播放器！")
            return
        """停止播放视频"""
        print('停止线程中......')
        await self.video_player.Stop()

      
    # 线程函数，每隔5秒往日志文件写入心跳
    def heartbeat(self):
        print("心跳包启动...")  
        while True:
            try:
                # 在这里写入心跳到日志文件的代码
                with open("heartbeat.log", 'w') as file:
                    file.write(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())) 
                print("Heartbeat")
                time.sleep(5)
            except:
                print("心跳写入异常！")
   
class VideoPlay:
    """视频播放类"""
    def __init__(self,_pathlist,_playtype,_websocket):
        """
        _pathlist:视频路径数组
        _playtype:播放类型one-播放一次 random-随机循环播放 list-顺序循环播放
        """
        self.pathlist = _pathlist
        """播放列表，存放播放路径"""
        self.playtype = _playtype
        """播放类型one-顺序播放一次 random-随机循环播放 list-顺序循环播放"""
        self.playing = ""
        """当前播放的视频"""
        self.IsPlaying = False
        """播放状态"""
        self.cam = None
        self.ws = _websocket
    def Play(self):
        self.thread = threading.Thread(target=self.playvideo)
        self.thread.start()
    def playvideo(self):
        self.IsPlaying = True
        # 初始化当前播放次数
        playtime = 1
        # //初始化摄像头
        videopath = self.pathlist[0]
        video = cv2.VideoCapture(videopath)
        width = int(video.get(cv2.CAP_PROP_FRAME_WIDTH))
        height = int(video.get(cv2.CAP_PROP_FRAME_HEIGHT))
        fps = video.get(cv2.CAP_PROP_FPS)
        print(width,height,fps)
        video.release()
        self.cam = pyvirtualcam.Camera(width=width, height=height, fps=fps)

        while self.IsPlaying:
            if playtime != 1:
                if self.playtype == "one":
                    if playtime > len(self.pathlist):
                        loop = asyncio.new_event_loop()
                        loop.run_until_complete(global_websocket.send("播放任务已结束"))
                        print('播放任务已结束')
                        break
                    else:
                        # 获取列表中下一条视频
                        nextvedio = self.get_next_element(self.pathlist,self.playing)
                        self.playing = nextvedio
                if self.playtype == "random":
                    # 随机获取一条除上次播放之外的视频
                    nextvedio = self.get_random_different_item(self.pathlist,self.playing)
                    self.playing = nextvedio
                if self.playtype == "list":
                    # 获取列表中下一条视频
                    nextvedio = self.get_next_element(self.pathlist,self.playing)
                    self.playing = nextvedio
            else:
                self.playing = self.pathlist[0]
            video = cv2.VideoCapture(self.playing)
            # self.ws.send("第"+str(playtime)+"次，开始播放："+self.playing)
            loop = asyncio.new_event_loop()
            loop.run_until_complete(global_websocket.send("第"+str(playtime)+"次，开始播放："+self.playing))
            print("第"+str(playtime)+"次，开始播放："+self.playing)
            # 帧速率
            rate = video.get(5) 
            # 帧数
            framenumber = video.get(7)
            # 总时长s
            duration =  framenumber/rate
            while self.IsPlaying:
                grabbed, frame = video.read()
                if not grabbed:
                    # self.ws.send("当前视频"+self.playing+"播放结束")
                    loop = asyncio.new_event_loop()
                    loop.run_until_complete(global_websocket.send("当前视频"+self.playing+"播放结束"))
                    print('当前视频播放结束')
                    break
                # 获取当前帧的帧数
                framenumb = video.get(cv2.CAP_PROP_POS_FRAMES)
                # 获取当前帧时间戳s
                timestamp= video.get(cv2.CAP_PROP_POS_MSEC)/1000
                # 打印帧数和时间戳
                loop = asyncio.new_event_loop()
                loop.run_until_complete(global_websocket.send("当前视频"+self.playing+"播放进度:"+f'{(timestamp/duration)*100:.2f}%'))
                # print(f'{(timestamp/duration)*100:.2f}%')
                frame = cv2.resize(frame,(self.cam.width,self.cam.height))
                frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
                self.cam.send(frame_rgb)
                self.cam.sleep_until_next_frame()
            video.release()
            playtime+=1
        self.cam.close()
    def get_next_element(self,string_list, target_string):
        """ 获取字符串在列表中的下一个元素，如果是最后一个则返回第一个
        """
        index = string_list.index(target_string)
        next_index = (index + 1) % len(string_list)
        return string_list[next_index]
    def get_random_different_item(self,string_list, current_item):
        """从列表中获取一个非当前项目的随机项目
        """
        if len(string_list)==1:
            return current_item
        # 从列表中排除当前项目
        other_items = [item for item in string_list if item != current_item]
        # 随机选择一个项目
        random_item = random.choice(other_items)
        return random_item
    async def Stop(self):
        self.IsPlaying = False
        self.thread.join()
# 启动视频服务
server = VideoServer()
server.start()
